package DFA;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import nfa_generator.NFANode;

public class DFAState implements DFAStateInterface {
	private final int id;
	private final Set<NFANode> nfaNodes;
	private final Map<String, DFAStateInterface> transitionToDFAState;
	private final String token;
	
	public DFAState (	int id,
						Set<NFANode> nfaNodes,
						Map<String, DFAStateInterface> transitionToDFAState) {
		this.id = id;
		this.nfaNodes = nfaNodes;
		this.transitionToDFAState = transitionToDFAState;
	
		String tmp = null;
		for (NFANode nfaNode : nfaNodes)
			if (nfaNode.isAccepting()) {
				if (tmp != null && !tmp.equals(nfaNode.getToken()))
					throw new IllegalArgumentException ("The nfaNodes contain more than 1 accepting NFANode with different tokens");
				else 
					tmp = nfaNode.getToken();
			}
		this.token = tmp;			
	}
	
	public DFAState (int id, Set<NFANode> nfaNodes) {
		this (id, nfaNodes, new HashMap<String, DFAStateInterface>());
	}
	
	public void buildTransitions() {
		Set<String> transitions = new HashSet<String>();
		for (NFANode nfaNode : nfaNodes) {
			transitions.addAll(nfaNode.getAllDistinctTransitions());
		}
		for (String transition : transitions) {
			if (!transition.equals("epsilon")) {
				Set<NFANode> nfaNodesSet = new HashSet<NFANode>();
				for (NFANode nfaNode : nfaNodes)
					nfaNodesSet.addAll(nfaNode.getTransition(transition));
				DFAStateInterface dfaState = DFAStateFactory.generate(nfaNodesSet);
				transitionToDFAState.put(transition, dfaState);
			}
		}
	}
	
	@Override
	public DFAStateInterface nextDFAState (String transition) {
		return transitionToDFAState.get(transition);
	}
	
	@Override
	public String getToken() {
		return token;
	}
	
	public Set<DFAStateInterface> getNeighbors() {
		Set<DFAStateInterface> output = new HashSet<DFAStateInterface>();
		output.addAll(transitionToDFAState.values());
		return output;
	}
	
	@Override
	public boolean isAccepting() {
		return token != null;
	}
	
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(id);
		sb.append("-------------------------------------------\n");
		sb.append("\t\tDFAState (id " + id + " ) contains:\n");
		sb.append("\tToken:" + token + "\n");
		sb.append("\tList of NFANode:\n");
		for (NFANode nfaNode : nfaNodes) {
			sb.append(nfaNode);
		}
		sb.append("-------------------------------------------\n");
		return sb.toString();
	}
	
	public void addTransision (String str, DFAStateInterface state) 
											  throws DFAException {
		if (transitionToDFAState.containsKey(str))
			throw new DFAException("Transition of a DFA state must not be modifiable");
		else 
			transitionToDFAState.put(str, state);
	}
}
